////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   objectlayermanager.cpp
//  Version:     v1.00
//  Created:     9/5/2003 by Timur.
//  Compilers:   Visual Studio.NET
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "ObjectLayerManager.h"
#include "ObjectLoader.h"
#include "GameEngine.h"
#include "ErrorReport.h"
#include "CheckOutDialog.h"

#include <IGameFramework.h>
#include <ISourceControl.h>
#include "EntityObject.h"
#include "RoadObject.h"
#include "HyperGraph/FlowGraphManager.h"
#include "HyperGraph/FlowGraph.h"
#include "HyperGraph/FlowGraphNode.h"

#include "TrackView/LayerNodeAnimator.h"


//////////////////////////////////////////////////////////////////////////
//! Undo Delete Layer
class CUndoLayerDelete : public IUndoObject
{
public:
	CUndoLayerDelete( CObjectLayer *obj )
	{
		m_object = obj;
		// Save current object state.
		m_undo = XmlHelpers::CreateXmlNode("Undo");
		obj->Serialize(m_undo, false);
	}
protected:
	virtual int GetSize() { return sizeof(*this); }; // Return size of xml state.
	virtual const char* GetDescription() { return "Delete Layer"; };

	virtual void Undo( bool bUndo )
	{
		TSmartPtr<CObjectLayer> pLayer = new CObjectLayer( GetIEditor()->GetObjectManager()->GetLayersManager() );
		pLayer->Serialize( m_undo, true );

		if (!GetIEditor()->GetObjectManager()->GetLayersManager()->FindLayer( pLayer->GetGUID() ))
			GetIEditor()->GetObjectManager()->GetLayersManager()->AddLayer( pLayer );

		GetIEditor()->GetObjectManager()->GetLayersManager()->ResolveLayerLinks();
	}
	virtual void Redo()
	{
		// Delete this object.
		GetIEditor()->GetObjectManager()->GetLayersManager()->DeleteLayer( m_object );
	}
private:
	//CBaseObjectPtr m_object;
	TSmartPtr<CObjectLayer> m_object;
	XmlNodeRef m_undo;
};



//////////////////////////////////////////////////////////////////////////
CObjectLayerManager::CObjectLayerManager( CObjectManager *pObjectManager )
{
	m_pObjectManager = pObjectManager;
	m_layersPath = LAYER_PATH;
	m_pMainLayer = 0;
	
	// Create main root level.
	//CreateMainLayer();
	m_bOverwriteDuplicates = false;
}

void CObjectLayerManager::GetLayers( std::vector<CObjectLayer*> &layers ) const
{
	layers.clear();
	layers.reserve( m_layersMap.size() );
	for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
	{
		layers.push_back( it->second );
	}
}

void CObjectLayerManager::CreateMainLayer(const GUID *pGUID)
{
	if(m_pMainLayer)
		return;
	m_pMainLayer = new CObjectLayer( this, pGUID );
	m_layersMap[m_pMainLayer->GetGUID()] = m_pMainLayer;
	m_pMainLayer->SetRemovable(true);
	m_pMainLayer->SetExternal(false);
	m_pMainLayer->SetName( "Main" );
	m_pMainLayer->Expand(true);
	m_pCurrentLayer = m_pMainLayer;
	NotifyListeners( ON_LAYER_UPDATEALL,NULL );
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ClearLayers()
{
	// Erase all removable layers.
	LayersMap::iterator it,itnext;
	for (LayersMap::iterator it = m_layersMap.begin(); it != m_layersMap.end(); it = itnext)
	{
		CObjectLayer *pLayer = it->second;
		itnext = it;
		itnext++;
		
		if (pLayer->IsRemovable())
		{
			NotifyListeners( ON_LAYER_REMOVE,pLayer );
			m_layersMap.erase( it );
		}
	}

	m_pMainLayer = 0;

	m_pCurrentLayer = 0;
	if (!m_layersMap.empty())
	{
		SetCurrentLayer( m_layersMap.begin()->second );
	}
	NotifyListeners( ON_LAYER_UPDATEALL,NULL );
}

//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::CreateLayer(const GUID *pGUID)
{
	if (pGUID)
	{
		CObjectLayer *pLayer = FindLayer(*pGUID);
		if (pLayer)
			return pLayer;
	}
	CObjectLayer *pLayer = new CObjectLayer( this, pGUID );
	m_layersMap[pLayer->GetGUID()] = pLayer;
	//m_pMainLayer->AddChild( pLayer );
	NotifyListeners( ON_LAYER_ADD,pLayer );
	//	pLayer->SetExternal(true);
	return pLayer;
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::AddLayer( CObjectLayer *pLayer )
{
	assert(pLayer);

	if (!m_bOverwriteDuplicates)
	{
		//CObjectLayer *pPrevLayer = FindLayerByName( pLayer->GetName() );
		//if (pPrevLayer)
		//{
		//	CErrorRecord err;
		//	err.error.Format( _T("Duplicate Layer Name <%s>"),(const char*)pLayer->GetName() );
		//	err.severity = CErrorRecord::ESEVERITY_ERROR;
		//	GetIEditor()->GetErrorReport()->ReportError(err);
		//	return;
		//}

		if (m_layersMap.find(pLayer->GetGUID()) != m_layersMap.end())
		{
			CObjectLayer *pPrevLayer = FindLayer(pLayer->GetGUID());

			CErrorRecord err;
			err.error.Format( _T("Duplicate Layer GUID,Layer <%s> collides with layer <%s>"),
				(const char*)pPrevLayer->GetName(),(const char*)pLayer->GetName() );
			err.severity = CErrorRecord::ESEVERITY_ERROR;
			GetIEditor()->GetErrorReport()->ReportError(err);
			return;
		}
	}

	m_layersMap[pLayer->GetGUID()] = pLayer;
	NotifyListeners( ON_LAYER_ADD,pLayer );
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::DeleteLayer( CObjectLayer *pLayer )
{
	assert( pLayer );
	// cannot remove non removable layer.
	if (!pLayer->IsRemovable())
		return;

	// one layer must exist.
	if(m_layersMap.size()<=1)
		return;

	if(pLayer == m_pMainLayer)
		m_pMainLayer = 0;

	// First delete all child layers.
	for (int i = 0; i < pLayer->GetChildCount(); i++)
	{
		DeleteLayer( pLayer->GetChild(i) );
	}

	// prevent reference counted layer to be released before this function ends.
	TSmartPtr<CObjectLayer> pLayerHolder = pLayer;

	// Delete all objects for this layer.
	std::vector<CBaseObjectPtr> objects;
	m_pObjectManager->GetAllObjects( objects );
	for (int k = 0; k < objects.size(); k++)
	{
		if (objects[k]->GetLayer() == pLayer)
			m_pObjectManager->DeleteObject(objects[k]);
	}

	if (GetIEditor()->IsUndoRecording())
		GetIEditor()->RecordUndo( new CUndoLayerDelete(pLayer) );

	// remove child from parent after serialization for storing Parent GUID
	if (pLayer->GetParent())
		pLayer->GetParent()->RemoveChild( pLayer );

	if (m_pCurrentLayer == pLayer)
		m_pCurrentLayer = pLayer->GetParent();
	m_layersMap.erase( pLayer->GetGUID() );

	//if (!m_pCurrentLayer)
		//m_pCurrentLayer = m_pMainLayer;
	if (!m_layersMap.empty())
	{
		SetCurrentLayer( m_layersMap.begin()->second );
	}

	NotifyListeners( ON_LAYER_REMOVE,pLayer );
	NotifyListeners( ON_LAYER_SELECT,m_pCurrentLayer );
	GetIEditor()->GetFlowGraphManager()->SendNotifyEvent( EHG_GRAPH_INVALIDATE );
}

//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::FindLayer( REFGUID guid ) const
{
	CObjectLayer *pLayer = stl::find_in_map( m_layersMap,guid,(CObjectLayer*)0 );
	return pLayer;
}

//////////////////////////////////////////////////////////////////////////
bool CObjectLayerManager::FindLayersByName( const CString &layerName,std::vector<CObjectLayer*>* layers ) const
{
	if (NULL != layers)
		layers->clear();
			
	for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
	{
		if (stricmp(it->second->GetName(),layerName) == 0)
		{
			if (NULL != layers)
				layers->push_back(it->second);
			else
				return true;
		}
	}

	if (NULL != layers)
		return !layers->empty();
	else
		return false;
}

CObjectLayer* CObjectLayerManager::FindLayerByFullPathName( const CString &layerFullPathName, const char *delimiter ) const
{
	std::vector<CString> chronicle;
	int delimiterLen = strlen(delimiter);
	int index = 0;
	int sp = layerFullPathName.Find(delimiter, index);
	while (sp != -1)
	{
		chronicle.push_back(layerFullPathName.Mid(index, sp));
		index = sp + delimiterLen;
		sp = layerFullPathName.Find(delimiter, index);
	}
	chronicle.push_back(layerFullPathName.Mid(index));

	std::vector<CObjectLayer*> leaves;
	FindLayersByName(chronicle.back(), &leaves);
	for (size_t i = 0; i < leaves.size(); ++i)
	{
		bool found = true;
		CObjectLayer* temp = leaves[i];
		for (int j = chronicle.size()-2; j >= 0; --j)
		{
			if (!temp->GetParent() || chronicle[j] != temp->GetParent()->GetName())
			{
				found = false;
				break;
			}
			temp = temp->GetParent();
		}

		if (temp->GetParent() != NULL)
			found = false;

		if (found)
			return leaves[i];
	}

	return NULL;
}

CObjectLayer* CObjectLayerManager::FindLayer( const CObjectLayer* pParent, const CString& layerName ) const 
{
	if (pParent)
	{
		for (int i = 0; i < pParent->GetChildCount(); ++i)
		{
			CObjectLayer* pLayer = pParent->GetChild(i);
			if (pLayer->GetName() == layerName)
				return pLayer;
		}
	}
	else
	{
		return FindLayerByFullPathName(layerName);
	}

	return NULL;
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::NotifyLayerChange( CObjectLayer *pLayer )
{
	assert(pLayer);
	// check if this layers is already registered in manager.
	if (m_layersMap.find(pLayer->GetGUID()) != m_layersMap.end())
	{
		// Notify listeners of this change.
		NotifyListeners( ON_LAYER_MODIFY,pLayer );
	}
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ChangeLayerWindowSize( )
{
	NotifyListeners( ON_LAYER_CHANGESIZE, 0 );
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::AddUpdateListener( const LayersUpdateCallback &cb )
{
	m_listeners.Add( cb );
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::RemoveUpdateListener( const LayersUpdateCallback &cb )
{
	m_listeners.Remove(cb);
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::NotifyListeners( EUpdateType type,CObjectLayer *pLayer )
{
	m_listeners.Call( type,pLayer );
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::Serialize( CObjectArchive &ar,bool bIgnoreExternalLayers )
{
	XmlNodeRef xmlNode = ar.node;
	if (ar.bLoading)
	{
		ClearLayers();
		// Loading from archive.

		XmlNodeRef layers = xmlNode->findChild( "ObjectLayers" );
		if (layers)
		{
			int nVers = 0;
			layers->getAttr("LayerVersion", nVers);
			if(nVers < 2)
				CreateMainLayer();

			for (int i = 0; i < layers->getChildCount(); ++i)
				LoadLayersRecursively(ar, layers->getChild(i), bIgnoreExternalLayers);
			
			GUID currentLayerGUID;
			if (layers->getAttr( "CurrentGUID",currentLayerGUID ))
			{
				CObjectLayer *pLayer = FindLayer( currentLayerGUID );
				if (pLayer)
					SetCurrentLayer( pLayer );
			}
		}

		if(!m_pCurrentLayer)
			CreateMainLayer();

		ResolveLayerLinks();
	}
	else
	{
		// Saving to archive.
		XmlNodeRef layersNode = xmlNode->newChild( "ObjectLayers" );
		int nVers = 2;
		layersNode->setAttr( "LayerVersion", nVers );

		//! Store currently selected layer.
		if (m_pCurrentLayer)
		{
			layersNode->setAttr( "Current",m_pCurrentLayer->GetName() );
			layersNode->setAttr( "CurrentGUID",m_pCurrentLayer->GetGUID() );
		}

		CCheckOutDialog::EnableForAll(true);
		for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
		{
			CObjectLayer *pLayer = it->second;
			if (!pLayer->IsRemovable())
				continue;

			if (NULL == pLayer->GetParent())
			{
				XmlNodeRef layerNode = layersNode->newChild("RootLayer");
				SaveLayersRecursively(ar, layerNode, pLayer, bIgnoreExternalLayers);
			}
		}
		CCheckOutDialog::EnableForAll(false);
	}
	ar.node = xmlNode;
}

void CObjectLayerManager::LoadLayersRecursively(CObjectArchive &ar, XmlNodeRef &layerNode, const bool bIgnoreExternalLayers)
{
	TSmartPtr<CObjectLayer> pLayer = new CObjectLayer( this );
	pLayer->Serialize( layerNode,true );
	if (pLayer->IsExternal())
	{
		if (!bIgnoreExternalLayers)
			LoadExternalLayer( pLayer->GetName(), pLayer->GetExternalLayerFileName(), ar );
	}
	else
	{
		// Check if this layer is already loaded.
		if (!FindLayer( pLayer->GetGUID() ))
			AddLayer( pLayer );
	}

	for (int i = 0; i < layerNode->getChildCount(); ++i)
		LoadLayersRecursively(ar, layerNode->getChild(i), bIgnoreExternalLayers);
}

void CObjectLayerManager::SaveLayersRecursively(CObjectArchive& ar, XmlNodeRef& layerNode, CObjectLayer* pLayer, const bool bIgnoreExternalLayers)
{
	pLayer->Serialize( layerNode,false );

	if (pLayer->IsExternal() && !bIgnoreExternalLayers)
	{
		if(!gSettings.saveOnlyModified || pLayer->IsModified())
		{
			// Save external level additionally to file.
			SaveExternalLayer( pLayer,ar );
		}

		// If this external layer is not marked as modified and saveOnlyModified option is used,
		// must iterate over any children of this layer and check to see if they need to be saved.
		// This is necessary because modified flags are local to the layer and child layers marked
		// as dirty do not propogate to the parent layer (i.e., parent can remain unmodified).
		else if (gSettings.saveOnlyModified)
		{
			CRY_ASSERT(!pLayer->IsModified());  // if modified, SaveExternalLayer() above should have handled it
			for (int i = 0; i < pLayer->GetChildCount(); ++i)
			{
				CObjectLayer* pChildLayer = pLayer->GetChild(i);
				if (pChildLayer->IsModified())
				{
					SaveExternalLayer( pChildLayer,ar );
				}
			}
		}
	}
	else
	{
		for (int i = 0; i < pLayer->GetChildCount(); ++i)
		{
			XmlNodeRef childLayer = layerNode->newChild("Layer");
			SaveLayersRecursively(ar, childLayer, pLayer->GetChild(i), bIgnoreExternalLayers);
		}
		pLayer->SetModified( false );
	}
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SaveExternalLayer( CObjectLayer *pLayer,CObjectArchive &ar )
{
	// Form file name from layer name.
	CString path = Path::AddBackslash( GetIEditor()->GetGameEngine()->GetLevelPath() ) + m_layersPath;
	CString file = path + pLayer->GetFullPathName(CObjectLayer::kExternalLayerPathDelimiter) + ".lyr";

	if(CFileUtil::OverwriteFile( file ))
	{
		CFileUtil::CreateDirectory( path );

		// Make a backup of file.
		if (gSettings.bBackupOnSave)
			CFileUtil::BackupFile( file );

		// Serialize this layer.
		XmlNodeRef rootFileNode = XmlHelpers::CreateXmlNode( "ObjectLayer" );
		XmlNodeRef layerNode = rootFileNode->newChild( "Layer" );
		ar.node = layerNode;
		ExportLayer( pLayer,ar,false ); // Also save all childs but not external layers.
		// Save xml file to disk.
		if (false == XmlHelpers::SaveXmlNode( rootFileNode,file ))
    {
			CString str;
			str.Format( _T("Couldn't export the layer: %s\nIs it valid path and filename?"),(const char*)file);
			AfxGetMainWnd()->MessageBox( str,_T("Failed to export!!"),MB_OK);
    }
		pLayer->SetModified( false );
	}
  else
  {
    CString str;
    str.Format( _T("Couldn't export the layer: %s\nIs it valid path and filename?"),(const char*)file);
    AfxGetMainWnd()->MessageBox( str,_T("Failed to export!!"),MB_OK);
  }
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::LoadExternalLayer( const CString &layerName,const CString &layerFullName,CObjectArchive &archive )
{
	// Form file name from layer name.
	CString file = Path::AddBackslash( GetIEditor()->GetGameEngine()->GetLevelPath() );
	file += m_layersPath + layerFullName + LAYER_FILE_EXTENSION;

	XmlNodeRef root = XmlHelpers::LoadXmlFromFile( file );
	if (!root)
	{
		// For the compatibility issue, try to find the layer file in old name convention.
		file = Path::AddBackslash( GetIEditor()->GetGameEngine()->GetLevelPath() );
		file += m_layersPath + layerName + LAYER_FILE_EXTENSION;
		root = XmlHelpers::LoadXmlFromFile( file );
		if (!root)
		{
			CErrorRecord err;
			err.error.Format( _T("Failed to import external object layer <%s> from File %s"),(const char*)layerName,(const char*)file );
			err.file = file;
			err.severity = CErrorRecord::ESEVERITY_ERROR;
			archive.ReportError(err);

			return;
		}
	}

	XmlNodeRef layerDesc = root->findChild("Layer");
	if (layerDesc)
	{
		XmlNodeRef prevRoot = archive.node;
		archive.node = layerDesc;
		m_bOverwriteDuplicates = true;
		CObjectLayer* pLayer = ImportLayer( archive,false );
		m_bOverwriteDuplicates = false;
		archive.node = prevRoot;

		uint32 attr = GetIEditor()->GetSourceControl()->GetFileAttributes( file );
		if(gSettings.freezeReadOnly && pLayer && attr!=SCC_FILE_ATTRIBUTE_INVALID && ( attr & SCC_FILE_ATTRIBUTE_READONLY))
			pLayer->SetFrozen(true);
	}
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ExportLayer( CObjectLayer *pLayer,CObjectArchive &ar,bool bExportExternalChilds )
{
	pLayer->Serialize( ar.node,false );

	XmlNodeRef orgNode = ar.node;
	XmlNodeRef layerObjects = ar.node->newChild("LayerObjects");
	ar.node = layerObjects;

	std::vector<CBaseObject*> objects;
	GetIEditor()->GetObjectManager()->GetObjects( objects,pLayer );
	// Save all objects to XML.
	for (int i = 0; i < objects.size(); i++)
	{
		ar.SaveObject( objects[i] );
	}

	if (pLayer->GetChildCount() > 0)
	{
		XmlNodeRef childLayers = orgNode->newChild("ChildLayers");
		// Export layer childs.
		for (int i = 0; i < pLayer->GetChildCount(); i++)
		{
			CObjectLayer *pChildLayer = pLayer->GetChild(i);
			XmlNodeRef childLayer = childLayers->newChild("Layer");
			ar.node = childLayer;
			if (pChildLayer->IsExternal() && !bExportExternalChilds)
			{
				pChildLayer->Serialize( ar.node,false );
				SaveExternalLayer(pChildLayer, ar);
				continue;
			}

			ExportLayer( pChildLayer,ar,bExportExternalChilds );
		}
	}

	ar.node = orgNode;
}

//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::ImportLayer( CObjectArchive &ar,bool bResolveObjects )
{
	XmlNodeRef layerNode = ar.node;
	if (stricmp(layerNode->getTag(),"Layer") != 0)
	{
		CErrorRecord err;
		err.error.Format( _T("Not a valid Layer XML Node %s, Must be \"Layer\""),(const char*)layerNode->getTag() );
		err.severity = CErrorRecord::ESEVERITY_WARNING;
		ar.ReportError(err);

		//Warning( "Not a valid Layer XML Node" );
		// Bad layer,Import fails.
		return 0;
	}
	TSmartPtr<CObjectLayer> pLayer = new CObjectLayer( this );
	pLayer->Serialize( layerNode,true );

	CString layerName = pLayer->GetName();

	bool bRemoveLayer = false;
	CObjectLayer *pPrevLayer = FindLayer( pLayer->GetGUID() );
	if (pPrevLayer)
	{
		if (m_bOverwriteDuplicates)
		{
			pLayer = pPrevLayer;
			pLayer->Serialize( layerNode,true ); // Serialize it again.
		}
		else
		{
			// Duplicate layer imported.
			CString layerName = pPrevLayer->GetName();
			bRemoveLayer = true;
			CString str;
			str.Format( _T("Replace Layer %s?\r\nAll object of replaced layer will be deleted."),(const char*)layerName );
			if (AfxGetMainWnd()->MessageBox( str,_T("Confirm Replace Layer"),MB_YESNO|MB_ICONQUESTION) == IDNO)
			{
				return 0;
			}
			DeleteLayer(pPrevLayer);
		}
	}

	if (pLayer)
	{
		AddLayer( pLayer );
	}

	XmlNodeRef layerObjects = layerNode->findChild("LayerObjects");
	if (layerObjects)
	{
		int numObjects = layerObjects->getChildCount();
		if (bResolveObjects)
			m_pObjectManager->StartObjectsLoading( numObjects );

		CObjectLayer * pCurLayer = m_pCurrentLayer;
		m_pCurrentLayer = pLayer;
		//ar.node = layerObjects;
		//m_pObjectManager->LoadObjects( ar,false );
		ar.LoadObjects( layerObjects );
		m_pCurrentLayer = pCurLayer;

		if (bResolveObjects)
			m_pObjectManager->EndObjectsLoading();
	}

	XmlNodeRef childLayers = layerNode->findChild("ChildLayers");
	if (childLayers)
	{
		// Import child layers.
		for (int i = 0; i < childLayers->getChildCount(); i++)
		{
			XmlNodeRef childLayer = childLayers->getChild(i);
			bool isExternal = false;
			childLayer->getAttr("External", isExternal);
			if (isExternal)
			{
				CString childLayerName, childLayerExternalFileName;
				childLayer->getAttr("Name", childLayerName);
				childLayer->getAttr("FullName", childLayerExternalFileName);
				LoadExternalLayer(childLayerName, childLayerExternalFileName, ar);
				continue;
			}

			ar.node = childLayer;
			CObjectLayer *pChildLayer = ImportLayer( ar,false );
			if (pChildLayer)
			{
				// Import child layers.
				pLayer->AddChild( pChildLayer );
			}
		}
		ar.node = layerNode;
	}

	if (bResolveObjects)
	{
		ResolveLayerLinks();
		ar.ResolveObjects();
	}

	return pLayer;
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SetCurrentLayer( CObjectLayer* pCurrLayer )
{
	assert( pCurrLayer );
	if (pCurrLayer == m_pCurrentLayer)
		return;
	m_pCurrentLayer = pCurrLayer;
	NotifyListeners( ON_LAYER_SELECT,m_pCurrentLayer );
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ResolveLayerLinks()
{
	for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
	{
		CObjectLayer *pLayer = it->second;
		if (!pLayer->IsRemovable())
			continue;

		// Try to connect to parent layer.
		CObjectLayer *pNewParent = FindLayer( pLayer->m_parentGUID );

		/*
		if (pNewParent == NULL && pLayer->GetParent() == m_pMainLayer)
		{
			// If parent is already main layer, skip.
			continue;
		}
		*/
		
		if (pLayer->GetParent() != NULL && pLayer->GetParent() != pNewParent)
		{
			// Deatch from old parent layer.
			pLayer->GetParent()->RemoveChild( pLayer );
		}
		if (pNewParent)
		{
			// Attach to new parent layer.
			pNewParent->AddChild( pLayer );
		}

		/*
		if (pLayer->GetParent() == NULL)
		{
			// all removable layers without parent must be attached to main layer.
			m_pMainLayer->AddChild( pLayer );
		}
		*/
	}
	NotifyListeners( ON_LAYER_UPDATEALL,0 );
}


//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::RemoveLayerSwitch(CObjectLayer* pLayer)
{
	for(int i=0; i<pLayer->GetChildCount(); i++)
	{
		RemoveLayerSwitch(pLayer->GetChild(i));
	}
	for (std::list<CObjectLayer*>::iterator it = m_layerSwitches.begin(); it != m_layerSwitches.end(); ++it)
		if(*it==pLayer)
		{
			m_layerSwitches.erase(it);
			break;
		}
}


//////////////////////////////////////////////////////////////////////////
bool CObjectLayerManager::AddLayerSwitch(CObjectLayer* pLayer)
{
	// avoid duplicates
	for (std::list<CObjectLayer*>::iterator it = m_layerSwitches.begin(); it != m_layerSwitches.end(); ++it)
		if(*it==pLayer)
			return false;

	for(int i=0; i<pLayer->GetChildCount(); i++)
	{
		RemoveLayerSwitch(pLayer->GetChild(i));
	}
	m_layerSwitches.push_back(pLayer);
	for(int i=0; i<pLayer->GetChildCount(); i++)
	{
		AddLayerSwitch(pLayer->GetChild(i));
	}
	return true;
}


//////////////////////////////////////////////////////////////////////////
bool CObjectLayerManager::InitLayerSwitches(bool isOnlyClear)
{
	if(isOnlyClear && m_layerSwitches.size())
	{
		std::vector<CBaseObjectPtr> objects;
		m_pObjectManager->GetAllObjects( objects );

		for (std::list<CObjectLayer*>::iterator it = m_layerSwitches.begin(); it != m_layerSwitches.end(); ++it)
		{
			CObjectLayer* pLayer = (*it);

			if(!pLayer->GetLayerID())
				continue;

			if(gEnv->pEntitySystem)
				gEnv->pEntitySystem->EnableLayer(pLayer->GetName(), true);

			for (int k = 0; k < objects.size(); k++)
			{
				CBaseObject* pObj = objects[k];
				if (pObj->GetLayer() == pLayer)
				{
					if(pObj->IsKindOf(RUNTIME_CLASS(CRoadObject)))
					{
						CRoadObject* pRoad = (CRoadObject*)pObj;
						pRoad->SetLayerId(0);
						if(!pLayer->IsPhysics())
							pRoad->SetPhysics(true); // restore init state
					}
					else if(!pObj->IsKindOf(RUNTIME_CLASS(CEntityObject)) || !((CEntityObject*)pObj)->GetIEntity())
					{
						IRenderNode* pRenderNode = pObj->GetEngineNode();
						if(pRenderNode)
						{
							pRenderNode->SetLayerId(0);
							pRenderNode->SetRndFlags(pRenderNode->GetRndFlags() & ~ERF_NO_PHYSICS);
						}
					}
				}
			}
			pLayer->SetLayerID(0);
		}
	}

	m_layerSwitches.clear();
	if(isOnlyClear)
		return true;

	bool bRet = false;

	if(gEnv->pFlowSystem && GetIEditor()->GetFlowGraphManager())
	{
		const TFlowNodeId layerTypeId = gEnv->pFlowSystem->GetTypeId("Engine:LayerSwitch");
		CFlowGraphManager * pEditorFGMan = GetIEditor()->GetFlowGraphManager();
		for(int i=0; i<pEditorFGMan->GetFlowGraphCount(); i++)
		{
			CFlowGraph* pEditorFG = pEditorFGMan->GetFlowGraph(i);

			IHyperGraphEnumerator* pEnum = pEditorFG->GetNodesEnumerator();
			for (IHyperNode* pINode = pEnum->GetFirst(); pINode; pINode = pEnum->GetNext())
			{
				if( !((CHyperNode*)pINode)->IsFlowNode() || ((CHyperNode*)pINode)->GetFlowNodeId()==InvalidFlowNodeId)
					continue;

				CFlowNode* pEditorFN = (CFlowNode*)pINode;
				if(pEditorFN->GetTypeId()==layerTypeId)
				{
					_smart_ptr<CVarBlock> pVarBlock = pEditorFN->GetInputsVarBlock();
					if(pVarBlock)
					{
						IVariable* pVar = pVarBlock->FindVariable("Layer");
						CString layerName;
						pVar->Get(layerName);

						CObjectLayer* pLayer = FindLayerByName_Workaround(layerName);
						if(pLayer && AddLayerSwitch(pLayer))
							bRet = true;
					}
				}
			}
		}
	}

	// Check the track view if there is a layer node.
	if(gEnv->pMovieSystem)
	{
		for(int k=0; k<GetIEditor()->GetMovieSystem()->GetNumSequences(); ++k)
		{
			IAnimSequence *seq = GetIEditor()->GetMovieSystem()->GetSequence(k);
			int nodeCount = seq->GetNodeCount();
			for(int i=0; i<nodeCount; ++i)
			{
				IAnimNode* pNode = seq->GetNode(i);
				if(pNode && pNode->GetType()==ANODE_LAYER)
				{
					CObjectLayer* pLayer = FindLayerByName_Workaround(pNode->GetName());
					if(pLayer && AddLayerSwitch(pLayer))
						bRet = true;
				}
			}
		}
	}
	
	return bRet;
}

// After the same name within the layers is allowed in SDK branch,
// you should use FindLayerByFullPathName() to identify unique layer.
// For the compatibility with other branches, a tricky code is provided.
CObjectLayer* CObjectLayerManager::FindLayerByName_Workaround(const CString& layerName)
{
	CObjectLayer* pLayer = FindLayerByFullPathName(layerName);
	if (pLayer)
		return pLayer;

	std::vector<CObjectLayer*> layers;
	if (FindLayersByName(layerName, &layers) && (layers.size() == 1))
		return layers[0];
	return NULL;
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ExportLayerSwitches(XmlNodeRef &node)
{
	if(m_layerSwitches.size()==0)
		return;
	XmlNodeRef layersNode = node->newChild( "Layers" );
	for (std::list<CObjectLayer*>::iterator it = m_layerSwitches.begin(); it != m_layerSwitches.end(); ++it)
	{
		CObjectLayer* pLayer = *it;
		XmlNodeRef layerNode = layersNode->newChild( "Layer" );
		layerNode->setAttr("Name", pLayer->GetName());
		layerNode->setAttr("Parent", pLayer->GetParent() ? pLayer->GetParent()->GetName() : "");
		layerNode->setAttr("Id", pLayer->GetLayerID());
		if(!pLayer->IsPhysics())
			layerNode->setAttr("Physics", 0);
		if (pLayer->IsDefaultLoaded())
			layerNode->setAttr("DefaultLoaded", 1);
	}
}


//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SetupLayerSwitches(bool isOnlyClear, bool isOnlyRenderNodes)
{
	if(!isOnlyRenderNodes)
	{
		if(!gEnv->pEntitySystem)
			return;

		gEnv->pEntitySystem->ClearLayers();
	}
	std::vector<CBaseObjectPtr> objects;
	m_pObjectManager->GetAllObjects( objects );

	if(!isOnlyRenderNodes && isOnlyClear)
	{
		// Show brashes in the end of game mode
		gEnv->p3DEngine->ActivateObjectsLayer(~0, true, true, "ALL_OBJECTS");

		// Update visibility for hidden brushes
		for (int k = 0; k < objects.size(); k++)
		{
			CBaseObject* pObj = objects[k];
			if(!pObj->IsKindOf(RUNTIME_CLASS(CEntityObject)) && pObj->IsHidden())
			{
				pObj->UpdateVisibility(true); // need for invalidation
				pObj->UpdateVisibility(false);
			}
		}
		return;
	}


	CObjectLayer* pPrevLayer = 0;
	uint16 curLayerId=0;

	for (std::list<CObjectLayer*>::iterator it = m_layerSwitches.begin(); it != m_layerSwitches.end(); ++it)
	{
		CObjectLayer* pLayer = (*it);

		for (int k = 0; k < objects.size(); k++)
		{
			CBaseObject* pObj = objects[k];
			
			// Skip hidden brushes in Game mode
			if(!isOnlyRenderNodes && (pObj->IsHidden() || pObj->IsHiddenBySpec()))
				continue;

			if (pObj->GetLayer() == pLayer)
			{
				if(pObj->IsKindOf(RUNTIME_CLASS(CRoadObject)))
				{
					if(!pLayer->GetLayerID())
						pLayer->SetLayerID(++curLayerId);
					CRoadObject* pRoad = (CRoadObject*)pObj;
					pRoad->SetLayerId(pLayer->GetLayerID());
					if(!pLayer->IsPhysics())
						pRoad->SetPhysics(false);
				}
				else if(!pObj->IsKindOf(RUNTIME_CLASS(CEntityObject)) || !((CEntityObject*)pObj)->GetIEntity())
				{
					IRenderNode* pRenderNode = pObj->GetEngineNode();
					if(pRenderNode)
					{
						if(!pLayer->GetLayerID())
							pLayer->SetLayerID(++curLayerId);
						pRenderNode->SetLayerId(pLayer->GetLayerID());
						if(!pLayer->IsPhysics())
							pRenderNode->SetRndFlags(pRenderNode->GetRndFlags() | ERF_NO_PHYSICS);
					}
				}
			}
		}

		if(!isOnlyRenderNodes)
		{
			gEnv->pEntitySystem->AddLayer(pLayer->GetName(), pLayer->GetParent() && pLayer->GetParent()==pPrevLayer ? pLayer->GetParent()->GetName() : "", pLayer->GetLayerID(), pLayer->IsPhysics(), pLayer->IsDefaultLoaded() );
			pPrevLayer = pLayer;

			for (int k = 0; k < objects.size(); k++)
			{
				CBaseObject* pObj = objects[k];
				if (pObj->GetLayer() == pLayer)
				{
					if(pObj->IsKindOf(RUNTIME_CLASS(CEntityObject)) && ((CEntityObject*)pObj)->GetIEntity())
						gEnv->pEntitySystem->AddEntityToLayer(pLayer->GetName(), ((CEntityObject*)pObj)->GetEntityId());
				}
			}
		}
	}

	// Hide brashes when Game mode is started
	if(!isOnlyRenderNodes)
		gEnv->p3DEngine->ActivateObjectsLayer(~0, false, true, "ALL_OBJECTS");
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SetLayerNodeAnimators(IAnimSequence* pSequence, bool isOnlyClear)
{
	if(!pSequence)
		return;
	int nodeCount = pSequence->GetNodeCount();
	for(int i=0; i<nodeCount; ++i)
	{
		IAnimNode* pNode = pSequence->GetNode(i);
		if(pNode && pNode->GetType()==ANODE_LAYER)
		{
			if(isOnlyClear)
				pNode->SetNodeAnimator(0);
			else
				pNode->SetNodeAnimator((IAnimNodeAnimator*)GetOrCreateLayerNodeAnimator());
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SetLayerNodeAnimators(IMovieSystem* pMovieSystem, bool isOnlyClear)
{
	for(int k=0; k<pMovieSystem->GetNumSequences(); ++k)
	{
		IAnimSequence *seq = pMovieSystem->GetSequence(k);
		SetLayerNodeAnimators(seq, isOnlyClear);
	}
}

//////////////////////////////////////////////////////////////////////////
CLayerNodeAnimator* CObjectLayerManager::GetOrCreateLayerNodeAnimator()
{
	if(!m_layerNodeAnimator)
		m_layerNodeAnimator = new CLayerNodeAnimator();

	return static_cast<CLayerNodeAnimator*>(m_layerNodeAnimator.get());
}

//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SetGameMode( bool inGame )
{
	if(InitLayerSwitches(!inGame))
		SetupLayerSwitches(!inGame);

	if(gEnv->pMovieSystem)
	{
		if(inGame)
			SetLayerNodeAnimators(gEnv->pMovieSystem, true);
		else
			SetLayerNodeAnimators(gEnv->pMovieSystem, false);
	}
}


void CObjectLayerManager::SaveUserSpecificData(XmlNodeRef& node)
{
	XmlNodeRef objectLayersNode = node->newChild("ObjectLayers");
	for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
	{
		CObjectLayer* layer = it->second;
		if (NULL == layer)
			continue;

		XmlNodeRef layerNode = objectLayersNode->newChild("Layer");
		layerNode->setAttr("Name", layer->GetExternalLayerFileName());
		layerNode->setAttr("GUID", layer->GetGUID());
		layerNode->setAttr("Hidden", !layer->IsVisible());
		layerNode->setAttr("Frozen", layer->IsFrozen());
	}
}

void CObjectLayerManager::LoadUserSpecificData(XmlNodeRef& node)
{
	XmlNodeRef objectLayerNode = node->findChild("ObjectLayers");
	for (int i = 0; i < objectLayerNode->getChildCount(); ++i)
	{
		XmlNodeRef layerNode = objectLayerNode->getChild(i);

		GUID guid;
		ZeroStruct(guid);
		layerNode->getAttr("GUID", guid);
		CObjectLayer* layer = FindLayer(guid);
		if (NULL == layer)
			continue;

		bool isHidden = false, isFrozen = false;
		layerNode->getAttr("Hidden", isHidden);
		layerNode->getAttr("Frozen", isFrozen);
		layer->SetVisible(!isHidden);
		layer->SetFrozen(isFrozen);
	}
}
